package GUI;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.html.HTMLDocument.Iterator;

import spreadsheet.Cell;

public class GUI {
	/**
	 * The JFrame to hold the Spreadsheet program
	 */
	private JFrame my_frame;
	/**
	 * The menubar at the top of my_frame
	 */
	private JMenuBar my_menuBar;
	/**
	 * Holds current cell value and row and column sizes.
	 */
	private InfoPanel my_infoPanel;
	/**
	 * Holds the FunctionPanel
	 */
	private JPanel my_bottomPanel;
	/**
	 * A panel that will contain access to several functions such as sum, min, max, etc
	 */
	private FunctionPanel my_functionPanel;
	/**
	 * Container for the various SpreadsheetFrames.
	 */
	private JDesktopPane my_desktop;
	/**
	 * Holds the multiple SpreadSheetFrames that will be displayed in the desktop pane.
	 */
	private ArrayList<SpreadSheetFrame> my_spreadSheets;
	/**
	 * The default width of my_frame
	 */
	private int WIDTH = 700;
	/**
	 * The default height of my_frame
	 */
	private int HEIGHT = 300;
	/**
	 * The default height of the rows.
	 */
	private int my_row_height = 15;
	/**
	 * The default width of the columns.
	 */
	private int my_column_width = 50;
	/**
	 * the minimum size of my_frame
	 */
	private Dimension my_min_size;
	/**
	 * A refenrence to this GUI.  Needed for use in ActionListeners
	 */
	private GUI myself;
	/**
	 * A Cell to hold the current Cell
	 */
	private Cell my_current_cell = null;
	/**
	 * A JTextField to hold the current JText field.
	 */
	private JTextField my_current_text_field = null;
	/**
	 * If the shift key is being held down this is set to true, if not if holds a value of false.
	 */
	private boolean isShiftDown = false;

	/**
	 * public constructor to create the GUI.
	 */
	public GUI() {
		myself = this;
		my_frame = new JFrame(
				"Abraham's and James' most awesome spreadsheet program for TCSS 342 - Fall 2012");
		my_min_size = new Dimension(WIDTH, HEIGHT);
		my_frame.setMinimumSize(my_min_size);
		my_frame.setJMenuBar(createMenuBar());
		my_frame.setLayout(new BorderLayout());

		my_infoPanel = new InfoPanel(this);
		my_frame.add(my_infoPanel.getPanel(), BorderLayout.NORTH);
		my_desktop = new JDesktopPane();
		my_desktop.setBackground(Color.GRAY);
		my_frame.add(my_desktop, BorderLayout.CENTER);
		my_bottomPanel = new JPanel();
		my_functionPanel = new FunctionPanel();
		my_bottomPanel.add(my_functionPanel.getPanel());
		my_frame.add(my_bottomPanel, BorderLayout.SOUTH);
		my_frame.setVisible(true);
		my_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		my_spreadSheets = new ArrayList<SpreadSheetFrame>();

	}
	/**
	 * Create the menuBar for the GUI.
	 * @return menuBar A JMenuBar that will be added to my_frame.
	 */

	private JMenuBar createMenuBar() {
		// creates the items in the File menu
		JMenuBar menuBar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		fileMenu.setMnemonic(KeyEvent.VK_F);
		JMenuItem newItem = new JMenuItem("New");
		newItem.setMnemonic(KeyEvent.VK_N);
		// creates and ActionListener that opens a new window
		newItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				final JDialog dimensions = new JDialog(my_frame, "SpreadSheet Dimensions", true);
				JPanel windowPanel = new JPanel();
				windowPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
				JLabel infoLabel = new JLabel("Enter the number of rows and columns");
				windowPanel.add(infoLabel, BorderLayout.NORTH);
				JPanel dimensionPanel = new JPanel();
				// create the dimensionPanel
				dimensionPanel.setLayout(new BoxLayout(dimensionPanel, BoxLayout.X_AXIS));
				//adds the row label and text to the dimensionPanel
				JLabel rowLabel = new JLabel("Rows");
				dimensionPanel.add(rowLabel);
				final JTextField rowText = new JTextField(4);
				dimensionPanel.add(rowText);
				//adds the column label and text to the dimensionPanel
				JLabel columnLabel = new JLabel("Columns");
				dimensionPanel.add(columnLabel);
				final JTextField columnText = new JTextField(4);
				dimensionPanel.add(columnText);

				windowPanel.add(dimensionPanel, BorderLayout.CENTER);
				JPanel buttonPanel = new JPanel();
				buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
				JButton createButton = new JButton("Create");
				buttonPanel.add(createButton);
				// creates an actionlistener that creates and new spreadsheetframe.
				createButton.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						try {
							SpreadSheetFrame tempFrame = new SpreadSheetFrame(Integer.parseInt(rowText.getText()) ,
									Integer.parseInt(columnText.getText()), myself);
							tempFrame.getFrame().show();
							my_desktop.add(tempFrame.getFrame());
							my_spreadSheets.add(tempFrame);
							dimensions.dispose();
						} catch(NumberFormatException e) {
							JOptionPane.showMessageDialog(dimensions, "Row and column values must be entered" +
									" and must be an integer.");
						}
					}

				});
				createButton.setMnemonic(KeyEvent.VK_ENTER);
				JButton cancelButton = new JButton("Cancel");
				cancelButton.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						dimensions.dispose();
					}
				});
				buttonPanel.add(cancelButton);
				windowPanel.add(buttonPanel, BorderLayout.SOUTH);
				dimensions.add(windowPanel);
				dimensions.setSize(310, 115);
				dimensions.setVisible(true);

			}
		});

		fileMenu.add(newItem);
		JMenuItem exitItem = new JMenuItem("Exit");
		exitItem.setMnemonic(KeyEvent.VK_E);
		exitItem.addActionListener(new ExitHandler());
		fileMenu.add(exitItem);
		fileMenu.addSeparator();
		JMenuItem aboutItem = new JMenuItem("About");
		aboutItem.setMnemonic(KeyEvent.VK_A);
		aboutItem.addActionListener(new AboutHandler());
		fileMenu.add(aboutItem);
		menuBar.add(fileMenu);

		return menuBar;

	}
	/**
	 * Returns the widths of the columns.
	 * @return my_column_width
	 */
	public int getColumnWidth() {
		return my_column_width;
	}
	/**
	 * Returns the row heights
	 * @return my_row_heigth.
	 */
	public int getRowHeight() {
		return my_row_height;
	}
	/**
	 * Sets the height of the rows.
	 * @param the_height The new height of the rows.
	 */
	public void setRowHeight(final int the_height) {
		my_row_height = the_height;
	}
	/**
	 * Set the widths of the columns.
	 * @param the_width The new width of the columns.
	 */
	public void setColumnWidth(final int the_width) {
		my_column_width = the_width;
	}
	/**
	 * Gets the current cell.
	 * @return my_current_cell The current cell
	 */
	public Cell getCurrentCell() {
		return my_current_cell;
	}
	/**
	 * Sets the current cell
	 * @param the_cell The cell the be et as the current cell.
	 */
	public void setCurrentCell(final Cell the_cell) {
		my_current_cell = the_cell;
	}
	/**
	 * Gets the InfoPanel at the top of the frame.
	 * @return my_infoPanel The InfoPanel
	 */
	public InfoPanel getInfoPanel() {
		return my_infoPanel;
	}
	/**
	 * Evaluates the current cell and all of its dependents.
	 */
	public void evaluateCurrent() {
		my_current_cell.evaluateCell();
		updateDependents();
	}
	/**
	 * Gets the current JTextField.
	 * @return my_current_text_field The current JTextField.
	 */
	public JTextField getCurrentTextField() {
		return my_current_text_field;
	}
	/**
	 * Sets my_current_text_field to a JTextField
	 * @param the_field The JTextField to be set as the current.
	 */
	public void setCurrentTextField(JTextField the_field) {
		my_current_text_field = the_field;
	}
	/**
	 * Gets the ArrayList of SpreadShetFrames that have been added to the desktop.
	 * @return my_spreadSheets The ArrayList of spreadsheetframes.
	 */
	public ArrayList<SpreadSheetFrame> getSpreadSheets() {
		return my_spreadSheets;
	}
	/**
	 * Gets the JDeskTopPane that holds all of the SpreadSheetFrames
	 * @return my_desktop The JDeskTopPane.
	 */
	public JDesktopPane getDesktop() {
		return my_desktop;
	}
	/**
	 * Returns the frame that hold the GUI.
	 * @return my_frame The frame that holds the GUI.
	 */
	public JFrame getFrame() {
		return my_frame;
	}
	/**
	 * Public method that calls a private helper method that recursively updates the dependents of a
	 * cell.
	 */
	public void updateDependents() {
		updateDependents(my_current_cell.getDependsOnMeSet());
	}
	/**
	 * Private method that recursively updates the dependents of a cell.
	 * @param the_set The set of dependent cells to update.
	 */
	private void updateDependents(Set<Cell> the_set) {
		if(the_set.isEmpty()) {
			return;
		} else {
			java.util.Iterator<Cell> itr = the_set.iterator();
			Cell tempCell;
			while(itr.hasNext()){
				tempCell = itr.next();
				tempCell.evaluateCell();
				tempCell.getTextField().setText(tempCell.getCellValue());
				tempCell.getTextField().revalidate();
				tempCell.getTextField().repaint();
				tempCell.getTextField().setSize(my_column_width, my_row_height);
				updateDependents(tempCell.getDependsOnMeSet());
			}
		}
		my_frame.repaint();
	}
	/**
	 * Returns a boolean value for whether the shift key is being held down.  True if it is held
	 * down.
	 * @return
	 */
	public boolean isShift() {
		return isShiftDown;
	}
	/**
	 * Sets the value of isShiftDown.
	 * @param the_value The value that isShiftDown is to be set to.
	 */
	public void setShift(boolean the_value) {
		isShiftDown = the_value;
	}
	/**
	 * Gets the FunctionPanel at the bottom of the GUI.
	 * @return my_functionPanel The functionPanel at the bottom of the GUI.
	 */
	public FunctionPanel getFunctionPanel() {
		return my_functionPanel;
	}
	/**
	 * Private class to handle closing the application/
	 * @author abrahamsantini
	 *
	 */
	private class ExitHandler implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			System.exit(0);
		}
	}
	/**
	 * Private class to handle displaying the "about" memu.
	 * @author abrahamsantini
	 *
	 */
	private class AboutHandler implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			JOptionPane.showMessageDialog(my_frame, "Created by James and Abraham for TCSS 342");

		}

	}

}
